package com.xuzhiguang.lightnat.server.core.server.control.handler;

import com.xuzhiguang.lightnat.common.manager.ControlChannelManager;
import com.xuzhiguang.lightnat.common.message.NatMessage;
import com.xuzhiguang.lightnat.common.message.control.ControlAuthenticationRequest;
import com.xuzhiguang.lightnat.common.message.control.ControlAuthenticationResponse;
import com.xuzhiguang.lightnat.server.core.client.NatClient;
import com.xuzhiguang.lightnat.server.core.client.NatClientService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@ChannelHandler.Sharable
public class AuthenticationHandler extends SimpleChannelInboundHandler<NatMessage> {

    private final NatClientService natClientService;

    public AuthenticationHandler(NatClientService natClientService) {
        this.natClientService = natClientService;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, NatMessage msg) throws Exception {

        log.debug("control auth. channel:{}", ctx.channel());

        try {
            if (msg.getBody() instanceof ControlAuthenticationRequest) {
                NatClient natClient = natClientService.getNatClient(((ControlAuthenticationRequest) msg.getBody()).getToken());

                ControlAuthenticationResponse response = new ControlAuthenticationResponse();

                if (natClient != null && natClient.getExpireTime() > System.currentTimeMillis()) {
                    response.setSuccess(true);
                    Channel oldChannel = ControlChannelManager.add(natClient.getId(), ctx.channel());
                    if (oldChannel != null) {
                        oldChannel.close();
                    }

                    log.info("control auth success. client id:{}", natClient.getId());
                } else {
                    response.setSuccess(false);
                    response.setErrMsg("invalid token");
                    log.warn("control auth fail. token:{}", ((ControlAuthenticationRequest) msg.getBody()).getToken());
                }
                ctx.channel().writeAndFlush(new NatMessage(response, msg.getHeader().getRequestId()));
                if (!response.getSuccess()) {
                    ctx.close();
                }

            } else {
                log.warn("expect first msg is auth request");
                ctx.close();
            }
        } finally {
            ctx.pipeline().remove(this);
        }
    }
}
